﻿using AForge.Video.FFMPEG;
using Baidu.Aip.Ocr;
using Baidu.Aip.Speech;
using SpeechLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AnalysisVideoSubtitle
{
    public partial class MainFrm : Form
    {
        public MainFrm()
        {
            InitializeComponent();
            //Control.CheckForIllegalCrossThreadCalls = false;
        }

        /// <summary>
        /// xy图片转换系数
        /// </summary>
        private float xyTrans;

        private Image Images;
        private Ocr client;
        private Tts ttsClient;
        private string lastTxt = "";

        /// <summary>
        /// 两张图标坐标转换系数
        /// </summary>
        private float Trans;

        /// <summary>
        /// 显示图片
        /// </summary>
        private bool showImage = false;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainFrm_Load(object sender, EventArgs e)
        {
            client = new Baidu.Aip.Ocr.Ocr(Data.API_KEY, Data.SECRET_KEY);
            ttsClient = new Baidu.Aip.Speech.Tts(Data.API_KEY, Data.SECRET_KEY);
            btnSave.Enabled = false;
            groupBox1.Enabled = false;
            btnStart.Enabled = false;
        }

        /// <summary>
        /// 选择文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                txtVideoUrl.Text = fileDialog.FileName;
                try
                {
                    VideoFileReader videoFileReader = new VideoFileReader();
                    videoFileReader.Open(txtVideoUrl.Text);
                    laW.Text = videoFileReader.Width.ToString();
                    laH.Text = videoFileReader.Height.ToString();
                    laTime.Text = ConvertTime(videoFileReader.FrameCount / videoFileReader.FrameRate);
                    var m = videoFileReader.ReadVideoFrame();
                    picFrist.Image = m.Clone() as Image;
                    Images = picFrist.Image.Clone() as Image;
                    ImageBoxSet(videoFileReader.Width, videoFileReader.Height);

                    m.Dispose();
                    videoFileReader.Close();
                }
                catch (Exception ex)
                {
                    txtVideoUrl.Text = "";
                    MessageBox.Show(ex.Message);
                }
            }
            //btnSelect.Enabled = false;
            groupBox1.Enabled = true;
        }

        /// <summary>
        /// 设置识别区域
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnSet_Click(object sender, EventArgs e)
        {
            if (numH.Value == 0 || numW.Value == 0)
            {
                MessageBox.Show("参数【高】【宽】必须大于0");
                return;
            }
            Image image = new Bitmap(Images.Width, Images.Height);
            Graphics g = Graphics.FromImage(image);//picFrist.CreateGraphics();
            g.Clear(Color.Green);
            g.DrawImage(Images, 0, 0);
            g.DrawRectangle(new Pen(Color.Red, 2f * xyTrans), (float)numX.Value * xyTrans, (float)numY.Value * xyTrans, (float)numW.Value * xyTrans, (float)numH.Value * xyTrans);
            picFrist.Image = image;

            showImage = ckShow.Checked;
            btnStart.Enabled = true;
        }

        /// <summary>
        /// 开始采集
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnStart_Click(object sender, EventArgs e)
        {
            btnSelect.Enabled = false;
            groupBox1.Enabled = false;
            btnStart.Enabled = false;

            Task task = new Task(() =>
            {
                VideoFileReader videoFileReader = new VideoFileReader();
                videoFileReader.Open(txtVideoUrl.Text);
                //for (int i = 0; i < videoFileReader.FrameCount; i++)
                //{
                //    var m = videoFileReader.ReadVideoFrame();
                //    if (i % (videoFileReader.FrameRate * numTime.Value) == 0)
                //    {
                //        Bitmap bit = img_tailor(m, new Rectangle((int)((int)numX.Value * Trans),
                //            (int)((int)numY.Value * Trans), (int)((int)numW.Value * Trans), (int)((int)numH.Value * Trans)));
                //        var r = client.GeneralBasic(Bitmap2Byte(bit));
                //        orgResult result = r.ToObject<orgResult>();
                //        StringBuilder sb = new StringBuilder();
                //        result.words_result.ForEach(p =>
                //        {
                //            sb.Append($"{p.words}\t");
                //        });
                //        if (sb.ToString().Trim() == lastTxt || sb.ToString().Trim().IsNullOrWhiteSpace())
                //            continue;
                //        write(sb.ToString().Trim(), ConvertTime(i / videoFileReader.FrameRate));
                //        lastTxt = sb.ToString().Trim();
                //    }
                //}
                var m = videoFileReader.ReadVideoFrame();
                long i = 0;
                while (m != null)
                {
                    i++;
                    if (i % (videoFileReader.FrameRate * numTime.Value) == 0)
                    {
                        Bitmap bit = img_tailor(m, new Rectangle((int)((int)numX.Value * Trans),
                            (int)((int)numY.Value * Trans), (int)((int)numW.Value * Trans), (int)((int)numH.Value * Trans)));
                        var r = client.GeneralBasic(Bitmap2Byte(bit));
                        orgResult result = r.ToObject<orgResult>();
                        StringBuilder sb = new StringBuilder();
                        result.words_result.ForEach(p =>
                        {
                            sb.Append($"{p.words}\t");
                        });
                        if (sb.ToString().Trim() == lastTxt || sb.ToString().Trim().IsNullOrWhiteSpace())
                            continue;
                        write(sb.ToString().Trim(), ConvertTime(i / videoFileReader.FrameRate));
                        lastTxt = sb.ToString().Trim();

                        if (showImage)
                            if (picFrist.InvokeRequired)
                                picFrist.Invoke(new Action<Bitmap>(p =>
                                {
                                    picFrist.Image = p;
                                }), m.Clone());
                            else
                                picFrist.Image = (Bitmap)m.Clone();
                    }
                    m = videoFileReader.ReadVideoFrame();
                    SetState(ConvertTime(i / videoFileReader.FrameRate));
                }
                SetState("解析结束");
                videoFileReader.Close();
            });
            task.Start();
            //task.Wait();
            btnSave.Enabled = true;
        }

        /// <summary>
        /// 设置状态
        /// </summary>
        /// <param name="str"></param>
        private void SetState(string str)
        {
            if (laIndexState.InvokeRequired)
            {
                laIndexState.Invoke(new Action<string>(p =>
                {
                    laIndexState.Text = p;
                }), str);
            }
            else
                laIndexState.Text = str;
        }


        /// <summary>
        /// 保存到文件中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnSave_Click(object sender, EventArgs e)
        {
            //btnSave.Enabled = false;
            SaveFileDialog openFileDialog = new SaveFileDialog();
            openFileDialog.Filter = "文本文件|*.txt";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                using (StreamWriter sw = new StreamWriter(openFileDialog.FileName, false, Encoding.UTF8))
                {
                    sw.Write(txtSubtitle.Text);
                    sw.Flush();
                }
                MessageBox.Show("保存成功");
                btnSelect.Enabled = true;
            }
        }

        /// <summary>
        /// 数字转换时间 00:00:00
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        private string ConvertTime(long time)
        {
            string shi = "00";
            string fen = "00";
            string miao = "00";
            shi = (time / 3600).ToString("00");
            time = time % 3600;
            fen = (time / 60).ToString("00");
            miao = (time % 60).ToString("00");
            return $"{shi}:{fen}:{miao}";
        }

        /// <summary>
        /// picbox 设置大小
        /// </summary>
        /// <param name="w"></param>
        /// <param name="h"></param>
        private void ImageBoxSet(float w, float h)
        {
            xyTrans = w / (float)300;
            if ((int)(h / xyTrans) > 390)
            {
                xyTrans = h / (float)300;
                picFrist.Height = 390;
                picFrist.Width = (int)(w / xyTrans);
            }
            else
            {
                picFrist.Width = 300;
                picFrist.Height = (int)(h / xyTrans);
            }
            numH.Maximum = (int)(h / xyTrans);
            numW.Maximum = (int)(w / xyTrans);
            numX.Maximum = (int)(w / xyTrans);
            numY.Maximum = (int)(h / xyTrans);
            Trans = (float)w / (float)picFrist.Width;
        }

        /// <summary>
        /// 写数据
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="time"></param>
        private void write(string msg, string time)
        {
            if (txtSubtitle.InvokeRequired)
                txtSubtitle.Invoke(new Action<string, string>((m, t) =>
                {
                    txtSubtitle.AppendText($"{t}：{m}\r\n");
                }), msg, time);
            else
                txtSubtitle.AppendText($"{time}：{msg}\r\n");
        }

        /// <summary>
        /// 图片转换2精致
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static byte[] Bitmap2Byte(Bitmap bitmap)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Jpeg);
                byte[] data = new byte[stream.Length];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(data, 0, Convert.ToInt32(stream.Length));
                return data;
            }
        }

        /// <summary>
        /// 图片剪裁
        /// </summary>
        /// <param name="src"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        public static Bitmap img_tailor(Bitmap src, Rectangle range)
        {
            return src.Clone(range, System.Drawing.Imaging.PixelFormat.DontCare);
        }

        /// <summary>
        /// 百度识别放回的类
        /// </summary>
        public class orgResult
        {
            public string direction { get; set; }
            public string log_id { get; set; }
            public string words_result_num { get; set; }
            public List<wordsresult> words_result { get; set; }
            public List<probability> probability { get; set; }
        }
        public class wordsresult
        {
            public string words { get; set; }
        }
        public class probability
        {
            public string average { get; set; }
            public string variance { get; set; }
            public string min { get; set; }
        }

        /// <summary>
        /// 语音配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnVoiceSet_Click(object sender, EventArgs e)
        {
            VoiceSetFrm voiceSetFrm = new VoiceSetFrm();
            voiceSetFrm.ShowDialog();
        }

        /// <summary>
        /// 合成语音
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnVoice_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(txtSubtitle.Text.Trim()))
                {
                    MessageBox.Show("文本为空");
                    return;
                }
                var option = new Dictionary<string, object>()
            {
                {"spd", Data.spd}, // 语速
                { "pit",Data.pit},//音调
                {"vol", Data.vol}, // 音量
                {"per", Data.per}  // 发音人，4：情感度丫丫童声
            };

                var result = ttsClient.Synthesis(txtSubtitle.Text.Trim(), option);

                if (result.ErrorCode == 0)  // 或 result.Success
                {
                    SaveFileDialog openFileDialog = new SaveFileDialog();
                    openFileDialog.Filter = "语音文件|*.mp3";
                    if (openFileDialog.ShowDialog() == DialogResult.OK)
                    {

                        File.WriteAllBytes(openFileDialog.FileName, result.Data);
                        //using (StreamWriter sw = new StreamWriter(openFileDialog.FileName, false, Encoding.UTF8))
                        //{
                        //    sw.Write(result.Data);
                        //    sw.Flush();
                        //}
                        MessageBox.Show("保存成功");
                    }
                }
                else
                {
                    MessageBox.Show($"{result.ErrorCode}:{result.ErrorMsg}");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"{ex.Message}");
            }
        }

        /// <summary>
        /// 直接阅读
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnRead_Click(object sender, EventArgs e)
        {
            Task task = new Task(() =>
            {
                setEnabled(false);
                SpVoice voice = new SpVoice();
                voice.Speak(txtSubtitle.Text.Trim());
                setEnabled(true);
            });
            task.Start();


        }

        public void setEnabled(bool isEnabled)
        {
            if (btnRead.InvokeRequired)
            {
                btnRead.Invoke(new Action<bool>(p =>
                {
                    btnRead.Enabled = p;
                }), isEnabled);
            }
            else
                btnRead.Enabled = isEnabled;
        }
    }
}
